#ifndef VET_CMD_HANDLER_UNITEST_H_
#define VET_CMD_HANDLER_UNITEST_H_

#include "unitest_comm.h"
#include "../include/vet_cmd_handler.h"
#include "../include/vet_system_status.h"
#include "../include/vet_protobuf_convertor.h"
#include <random>

UNITEST_NAMESPACE_BEGIN
class CmdHandlerTest : public testing::Test{
protected:
    virtual void SetUp() {
        vectorindex::ConfigManager::Instance()->InitConfig();

        const vectorindex::VectorIndexContext* p_vet_cnt = 
                    vectorindex::ConfigManager::Instance()->GetVectorIndexTable();

        stat_init_log_(p_vet_cnt->s_service_name_.c_str(),
                p_vet_cnt->s_log_dir_.c_str());
        stat_set_log_level_(p_vet_cnt->ui_log_level_);

        s_rocksdb_path_ = p_vet_cnt->s_rocksdb_dir_ + "/cmdhandelertest";

        p_cmd_handler = new vectorindex::CmdHandler(NULL);
    }
protected:
    vectorindex::CmdHandler* p_cmd_handler;
    std::mt19937 rng;
    std::uniform_real_distribution<> distrib;
    std::string s_rocksdb_path_;
};

TEST_F(CmdHandlerTest , Cmd_VetKeyFormat_Test){
    VetReqCnt o_vet_req_cnt;
    o_vet_req_cnt.o_idx_flag_.i_appid_ = 10008;
    o_vet_req_cnt.o_idx_flag_.i_field_id_ = 14;

    o_vet_req_cnt.o_vet_data_.emplace_back(0.001);
    o_vet_req_cnt.o_vet_data_.emplace_back(0.002);
    o_vet_req_cnt.o_vet_data_.emplace_back(0.003);
    o_vet_req_cnt.o_vet_data_.emplace_back(0.004);
    o_vet_req_cnt.o_vet_data_.emplace_back(0.005);
    o_vet_req_cnt.o_vet_data_.emplace_back(0.006);

    int i_vet_no = 1;
    int i_dim = 2;
    std::string s_format = vectorindex::CmdHandler::VetKeyFormat(o_vet_req_cnt , i_vet_no , i_dim);
    EXPECT_TRUE("10008#14#0.003|0.004|" == s_format);
};

TEST_F(CmdHandlerTest , TaskNotify_Test) {
    vectorindex::IndexFactory::Instance()->InitIndex();
    vectorindex::IndexFactory* p_vet_idx = vectorindex::IndexFactory::Instance();

        vectorindex::RocksDbOperator::Instance()->InitRocksDb(s_rocksdb_path_);

    std::string s_vet_id = "-1";
    int i_ret = vectorindex::RocksDbOperator::Instance()->GetEntry(
                        VET_CURRENT_NUM_KEY, 
                        s_vet_id , 
                        vectorindex::E_COL_FAM_META_DATA);

    std::cout<< "s_vet_id:"<< s_vet_id <<std::endl;
    vectorindex::SystemState::Instance()->SetVetId(s_vet_id);
    i_ret = vectorindex::SystemState::Instance()->AutoIncVetId();
    EXPECT_TRUE(0 == i_ret);

    int i_vet_id = (int64_t)strtoll(vectorindex::SystemState::Instance()->GetVetId().c_str(),NULL,10);

    CTaskRequest* p_ctask_req = new CTaskRequest();
    
    int i_dim = 128;
    int i_vet_num = 10;
    VectorReq o_vet_req;
    for (int i = 0; i < i_vet_num; i++) {
        for (int j = 0; j < i_dim; j++) {
            o_vet_req.add_vector_data(distrib(rng));
        }
    }
    o_vet_req.set_appid(10008);
    o_vet_req.set_field_id(14);
    o_vet_req.set_index_typeid(0);


    std::string s_parse_str;
    bool b_ret = o_vet_req.SerializeToString(&s_parse_str);
    EXPECT_TRUE(b_ret);

    VetReqCnt o_vet_req_cnt;
    b_ret = vectorindex::PbCvtor::ConvertPbStr2VetReqCnt(s_parse_str, o_vet_req_cnt);
    EXPECT_TRUE(b_ret);

    b_ret = p_ctask_req->copyOnePacket(s_parse_str.c_str() , s_parse_str.length());
    EXPECT_TRUE(b_ret);

    // add 
    p_ctask_req->SetReqCmd(SERVICE_VECTOR_ADD);

    p_cmd_handler->TaskNotify(p_ctask_req);

    std::string s_result = p_ctask_req->GetResultString();

    VectorRsp o_vet_rsp_pb;
    b_ret = o_vet_rsp_pb.ParseFromString(s_result);
    std::cout<< "vector info :" << o_vet_rsp_pb.info() <<std::endl;
    EXPECT_TRUE(b_ret);

    std::vector<float> vetcont_array(i_dim);
    for (int i = 0; i < o_vet_rsp_pb.vector_id_size(); i++) {
        std::cout<< "vector id :" << o_vet_rsp_pb.vector_id(i) <<std::endl;
        EXPECT_TRUE(i_vet_id <= (int)o_vet_rsp_pb.vector_id(i)
             && (int)o_vet_rsp_pb.vector_id(i) < i_vet_id + i_vet_num);

        // test index RAM, run twice ,because of vector is same , just return vet ids
        // no index ram 
        if (s_vet_id == "-1") {
            std::cout<< "index type id:" << o_vet_req_cnt.o_idx_flag_.i_index_typeid_ <<std::endl;
            int i_ret = (*p_vet_idx)[o_vet_req_cnt.o_idx_flag_]->ExtractVet(o_vet_rsp_pb.vector_id(i) 
                , vetcont_array.data());
            std::cout<< "i_ret:" << i_ret <<std::endl;
            EXPECT_TRUE(0 == i_ret);

            for (int j = 0; j < i_dim; j++) {
                EXPECT_TRUE(abs(o_vet_req_cnt.o_vet_data_[i*i_dim + j] - vetcont_array[j]) < 0.0001);
            }
        }
    }

    // id search
    p_ctask_req->SetReqCmd(SERVICE_VECTOR_QUERY_ID);
    p_cmd_handler->TaskNotify(p_ctask_req);

    s_result = p_ctask_req->GetResultString();

    VectorRsp o_vet_id_search_rsp_pb;
    b_ret = o_vet_id_search_rsp_pb.ParseFromString(s_result);
    EXPECT_TRUE(b_ret);

    for (int i = 0; i < o_vet_id_search_rsp_pb.vector_id_size(); i++) {
        std::cout<< "id search:" << o_vet_id_search_rsp_pb.vector_id(i) <<std::endl;
        EXPECT_TRUE(i_vet_id <= (int)o_vet_id_search_rsp_pb.vector_id(i) 
            && (int)o_vet_id_search_rsp_pb.vector_id(i) < i_vet_id + i_vet_num);
    }

    // delete 
    p_ctask_req->SetReqCmd(SERVICE_VECTOR_DELETE);
    p_cmd_handler->TaskNotify(p_ctask_req);

    s_result = p_ctask_req->GetResultString();

    VectorRsp o_vet_del_rsp_pb;
    b_ret = o_vet_del_rsp_pb.ParseFromString(s_result);
    EXPECT_TRUE(b_ret);

    EXPECT_TRUE(0 == o_vet_del_rsp_pb.code());
    std::cout<< o_vet_del_rsp_pb.info() <<std::endl;
};

UNITEST_NAMESPACE_END
#endif
